package com.idea.relax.log.publisher;

import com.idea.relax.log.annotation.ApiLog;
import com.idea.relax.log.constant.ApiLogConstant;
import com.idea.relax.log.event.ApiLogEvent;
import com.idea.relax.log.model.ApiLogModel;
import com.idea.relax.log.support.*;
import com.idea.relax.log.support.spel.EvaluationContextRootObject;
import com.idea.relax.log.support.utils.*;
import lombok.AllArgsConstructor;
import org.aopalliance.intercept.MethodInvocation;
import org.springframework.context.ApplicationEvent;

import java.util.HashMap;
import java.util.Map;
import java.util.Objects;

/**
 * @className: ApiLogPublisher
 * @description: 操作日志事件发布者
 * @author: salad
 * @date: 2022/6/3
 **/
@AllArgsConstructor
public class ApiLogPublisher implements ILogPublisher {

    private final ApplicationEvent event;

    /**
     * 构建ApiLogPublisher
     *
     * @param maxRespDataLength   最大保留的响应数据字节数
     * @param apiLog              操作日志注解
     * @param invocation          MethodInvocation
     * @param methodExecuteResult 方法执行结果状态上下文对象
     * @return ApiLogPublisher
     */
    public static ApiLogPublisher build(Integer maxRespDataLength,
                                        ApiLog apiLog, MethodInvocation invocation,
                                        MethodExecuteResult methodExecuteResult) {
        AspectMetadata aspectMetadata = new AspectMetadata();
        aspectMetadata.setMethodName(invocation.getMethod().getName());
        aspectMetadata.setTarget(invocation.getThis());
        aspectMetadata.setArgs(invocation.getArguments());
        aspectMetadata.setTargetClass(Objects.requireNonNull(invocation.getThis()).getClass());
        aspectMetadata.setMethod(invocation.getMethod());
        return build(maxRespDataLength, apiLog, aspectMetadata, methodExecuteResult);
    }

    /**
     * 构建ApiLogPublisher
     *
     * @param maxRespDataLength   最大保留的响应数据字节数
     * @param apiLog              操作日志注解
     * @param amd                 有关目标方法相关的切面数据
     * @param methodExecuteResult 方法执行结果状态上下文对象
     * @return ApiLogPublisher
     */
    public static ApiLogPublisher build(Integer maxRespDataLength,
                                        ApiLog apiLog, AspectMetadata amd,
                                        MethodExecuteResult methodExecuteResult) {
        String methodName = amd.getMethodName();
        //获取类名
        String className = Objects.requireNonNull(amd.getTarget()).getClass().getSimpleName();
        Map<String, Object> values = new HashMap<>(2);
        //获取注解的value值
        String title = apiLog.value();
        String description = apiLog.description();
        OperationType operationType = apiLog.operationType();
        boolean saveResponseData = apiLog.isSaveRespData();
        //使用model承载数据
        ApiLogModel model = new ApiLogModel();
        model.setOperationType(operationType.name());
        model.setTitle(title);
        model.setTime(methodExecuteResult.getTime());
        model.setMethodClass(className);
        model.setMethodName(methodName);
        model.setStatus(methodExecuteResult.getResponseStatus().getState());
        AppInfoProvider.appendRequestInfo(WebUtil.getRequest(), model);
        model.setDescription(description);
        if (saveResponseData && methodExecuteResult.getResult() != null) {
            model.setResponseData(subResponseData(methodExecuteResult.getResult(), maxRespDataLength));
        }
        values.put(ApiLogConstant.API_LOG_MODEL, model);
        EvaluationContextRootObject rootObject = new EvaluationContextRootObject();
        rootObject.setClassName(className);
        rootObject.setArgs(amd.getArgs());
        rootObject.setMethodName(methodName);
        rootObject.setMethod(amd.getMethod());
        rootObject.setTarget(amd.getTarget());
        rootObject.setTargetClass(amd.getTargetClass());
        values.put(ApiLogConstant.ROOT_OBJECT, rootObject);
        Wrapper<Map<String, Object>> wrapper = new Wrapper<>(values);
        return new ApiLogPublisher(new ApiLogEvent(wrapper));
    }


    @Override
    public void publish() {
        LogEventPublisher.publish(event);
    }

    /**
     * 截取响应数据
     *
     * @param result            响应数据
     * @param maxRespDataLength 最大保留的响应数据字节数
     * @return 截取之后的数据
     */
    private static String subResponseData(Object result, Integer maxRespDataLength) {
        if (result == null) {
            return null;
        }
        if (maxRespDataLength == null || maxRespDataLength == 0) {
            return JsonUtil.toJson(result);
        }
        String responseData = JsonUtil.toJson(result);
        if (responseData != null && responseData.length() > maxRespDataLength) {
            responseData = StringUtil.sub(responseData, 0, maxRespDataLength);
        }
        return responseData;
    }

}
